
/**
 * 每个 component 的 JS Script 运行后, 要不是 Dashboard 要不就是 function
 * 这个 monitors 定义了查看屏幕详情数据时的默认页 Vue 的创建函数, 以及其它页.
 * 
 * key:
 *   比如: ${series.toLowCast()}-${scene.toLowCast()}-main
 * 
 * value: Monitor
 * @type {Map<String, Monitor>}
 */
const monitors = {};

class Monitor {
  /**
   * @type {TabItem[]} 初始时的 tab. 事实上, 因为 tab 可能动态添加, 页面上显示的和这个可能不同
   */
  tabs = [];
  /**
   * @type {function}
   * 输入的是 context 以及 key, 输出的是 vue-comp-object
   */
  factory;
  /**
   * @param {function} factory 
   * @param {TabItem[]} tabs 
   */
  constructor(factory, tabs) {
    this.factory = factory;
    this.tabs = tabs;
  }
}

/**
 * @param {string} name 
 * @param {Monitor | null} monitor 
 */
function putMonitor(name, monitor) {
  return monitors[name] = monitor; // null -> delete
}

/**
 * @param {string} name
 * @returns {Monitor | null} 
 */
function getMonitor(name) {
  return monitors[name]; // may be null
}

function putScreenMonitor(name, obj) {
  if (typeof(obj) == 'function') {
    return putMonitor(name, new Monitor(
      obj, defaultScreenTabs()
    ));
  }

  if (typeof(obj) == 'object' && typeof(obj.factory) == 'function') {
    if (obj.tabs == null || !(obj.tabs instanceof Array)) {
      return putMonitor(name, new Monitor(obj.factory, defaultScreenTabs()));
    }

    let tabs = obj.tabs.map(tab => {
      let tab0 = new TabItem();
      Object.assign(tab0, tab);
      return tab0;
    });
    return putMonitor(name, new Monitor(obj.factory, defaultScreenTabs().concat(tabs)));
  }

  if (typeof(obj) == 'object' && typeof(obj.factory) == 'function'
      && (obj.tabs == null) || obj.tabs instanceof Array) {
    
    return putMonitor(name, new Monitor(
      obj.factory, defaultScreenTabs().concat(obj.tabs)
    ));
  }
}

class TabItem {
  /** @type string */
  key = null;
  /** @type string */
  name = null;
  /** @type string */
  icon = null;
  /** @type string */
  component = null;
  /**
   * @param {string} key 
   * @param {string} name 
   * @param {string} icon 
   * @param {string} component 
   */
  constructor(key, name, icon, component = 'content-wait') {
    this.key = key;
    this.name = name;
    this.icon = icon;
    this.component = component;
  }

  clone() {
    return new TabItem(this.key, this.name, this.icon, this.component);
  }
}

/**
 * @type {TabItem[]}
 */
let currentTabs = [];

function allTabs() {
  return currentTabs.map(tab => tab.clone());
}

/**
 * @param {TabItem[]} tabs 
 */
function resetTabs(tabs) {
  currentTabs = tabs.map(tab => tab.clone());
}

/**
 * @param  {...TabItem} tabs 
 * @returns  {TabItem[]}
 */
function putTab(...tabs) {
  let ret = [];
  tabs.forEach(tab => {
    if (currentTabs.filter(ctab => ctab.key == tab.key).length > 0) {
      return;
    }
    currentTabs.push(tab.clone());
    ret.push(tab);
  });
  return ret;
}

/**
 * @param  {...string} keys 
 * @returns  {TabItem[]}
 */
function deleteTab(...keys) {
  let ret = [];
  keys.forEach(key => {
    if (key == 'main' || key == 'situation') {
      console.error(`fail to delete tab: key = ${key}`);
      return;
    }

    let index = currentTabs.findIndex(tab => tab.key == key);
    if (index == -1) {
      return;
    }
    ret.concat(currentTabs.splice(index, 1));
  });
  return ret;
}

function situationTab() {
  return new TabItem('situation', '详情', 'monitor', 'body-screen-situation');
}

function mainTab() {
  return new TabItem('main', '仪表盘', 'dashboard');
}

function defaultScreenTabs() {
  return [ situationTab(), mainTab() ];
}

function defaultGeneralTabs() {
  return [
    new TabItem('main', '', '', ''),
  ];
}

/**
 * 跳路径
 */
class Jump {
  aside = 'general'; // general | screen | screenRemoved
  /**
   * aside='general', asideParam='';
   * aside='screen', asideParam=sid
   */
  asideParam = '';
  tabKey = '';
  clone() {
    return Object.assign(new Jump(), this);
  }
}

function createGeneralJump() {
  return new Jump();
}

function createScreenJump(sid, tabKey = 'main') {
  let jump = new Jump();
  jump.aside = 'screen';
  jump.asideParam = sid;
  jump.tabKey = tabKey;
  return jump;
}

function createScreenRemovedJump(sid) {
  let jump = new Jump();
  jump.aside = 'screenRemoved';
  jump.asideParam = sid;
  return jump;
}

export {
  TabItem, Monitor, Jump,
  getMonitor, putScreenMonitor,
  defaultScreenTabs, defaultGeneralTabs, allTabs, resetTabs, putTab, deleteTab,
  createGeneralJump, createScreenJump, createScreenRemovedJump,
};